package cn.kivensoft.util.impl;

import java.security.SecureRandom;
import java.util.Arrays;
import java.util.concurrent.locks.ReentrantLock;

public class BaseCrypt {

	// base64加密算法映射表
	protected static final char[] BASE64_DIGEST =
			"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray(); 
	// base64解密算法映射表
	private static volatile byte[] INDEX_64 = null;
	private static final ReentrantLock indexLock = new ReentrantLock();

	private final SecureRandom random;

	public BaseCrypt() {
		random = new SecureRandom();
	}

	private static void initIndex64() {
		if (INDEX_64 != null)
			return;

		byte[] idx = new byte[128];
		Arrays.fill(INDEX_64, (byte)-1);
		for (int i = 0, n = BASE64_DIGEST.length; i < n; ++i)
			idx[BASE64_DIGEST[i]] = (byte) i;
		idx['='] = 0;

		indexLock.lock();
		if (INDEX_64 == null)
			INDEX_64 = idx;
		indexLock.unlock();
	}

	/**
	 * base64加密算法
	 * @param data	需要加密的字节数组
	 * @return	加密后的base64字符串
	 */
	protected static String encodeBase64(byte[] data) {
		char[] digest = BASE64_DIGEST;
		int dataLen = data.length, alignCount = dataLen / 3, modCount = dataLen % 3;
		int alignLen = dataLen - modCount, str_len = alignCount * 4;
		if (modCount == 1) str_len += 2;
		else if (modCount == 2) str_len += 3;

		char[] str = new char[str_len];
		int str_off = -1;

		for (int i = 0; i < alignLen; i += 3) {
			int c1 = data[i] & 0xff;
			str[++str_off] = digest[(c1 >> 2) & 0x3f];

			c1 = (c1 & 0x03) << 4;

			int c2 = data[i + 1] & 0xff;
			c1 |= (c2 >> 4) & 0x0f;
			str[++str_off] = digest[c1 & 0x3f];

			c1 = (c2 & 0x0f) << 2;

			c2 = data[i + 2] & 0xff;
			c1 |= (c2 >> 6) & 0x03;
			str[++str_off] = digest[c1 & 0x3f];
			str[++str_off] = digest[c2 & 0x3f];
		}
		
		// 处理不对齐的字节数
		if (modCount != 0) {
			int mod_off = alignLen;
			int c1 = data[mod_off++] & 0xff;
			str[++str_off] = digest[(c1 >> 2) & 0x3f];
			c1 = (c1 & 0x03) << 4;
			if (mod_off < dataLen) {
				int c2 = data[mod_off] & 0xff;
				c1 |= (c2 >> 4) & 0x0f;
				str[++str_off] = digest[c1 & 0x3f];
				c1 = (c2 & 0x0f) << 2;
			}
			str[++str_off] = digest[c1 & 0x3f];

		}

		return new String(str);
	}

	/**
	 * 解码单个base64字符
	 * @param x	base64字符
	 * @return	解码后的值
	 */
	protected static byte char64(int x) {
		return (x < 0 || x > INDEX_64.length) ? -1 : INDEX_64[x];
	}

	/**
	 * 解码base64字符串
	 * @param text	base64字符串
	 * @return	解码后的字节数组
	 */
	protected static byte[] decodeBase64(String text) {
		if (INDEX_64 == null) initIndex64();

		int off = 0, slen = text.length(), olen = 0;
		int alignCount = slen / 4, modCount = slen % 4;
		int ret_len = alignCount * 3;
		if (modCount == 2) ret_len += 1;
		else if (modCount == 3) ret_len += 2;
		byte[] ret = new byte[ret_len];
		byte c1, c2, c3, c4, o, ret_off = -1;

		while (off < slen - 1 && olen < slen) {
			c1 = char64(text.charAt(off++));
			c2 = char64(text.charAt(off++));
			if (c1 == -1 || c2 == -1) break;

			o = (byte)(c1 << 2);
			o |= (byte) ((c2 & 0x30) >> 4);
			ret[++ret_off] = o;
			if (++olen >= slen || off >= slen) break;

			c3 = char64(text.charAt(off++));
			if (c3 == -1) break;
			o = (byte)((c2 & 0x0f) << 4);
			o |= (byte) ((c3 & 0x3c) >> 2);
			ret[++ret_off] = o;
			if (++olen >= slen || off >= slen) break;

			c4 = char64(text.charAt(off++));
			o = (byte)((c3 & 0x03) << 6);
			o |= c4;
			ret[++ret_off] = o;
			++olen;
		}

		return ret;
	}

	/** 创建随机盐值
	 * @param keyLen 秘钥长度
	 * @return 随机秘钥
	 */
	protected byte[] gensalt(int keyLen) {
		byte[] ret = new byte[keyLen];
		random.nextBytes(ret);
		return ret;
	}

}
